package com.hq.common.utils;

import java.sql.SQLException;
import java.util.*;

import com.hq.common.domain.SearchObject;
import com.hq.common.domain.SearchValue;
import org.hibernate.*;
import org.hibernate.criterion.DetachedCriteria;
import org.hibernate.criterion.Order;
import org.hibernate.criterion.Projections;
import org.hibernate.criterion.Restrictions;
import org.springframework.orm.hibernate3.HibernateCallback;
import org.springframework.orm.hibernate3.HibernateTemplate;

@SuppressWarnings("unchecked")
public class HibernateUtil {

	private static SessionFactory sessionFactory;
	private static HibernateTemplate hibernateTemplate;
	
	public static HibernateTemplate getTemplate() {
		return HibernateUtil.hibernateTemplate;
	}
	
	public static SessionFactory getSessionFactory() {
		return sessionFactory;
	}
	public void setSessionFactory(SessionFactory sessionFactory) {
		HibernateUtil.sessionFactory = sessionFactory;
		HibernateUtil.hibernateTemplate = new HibernateTemplate(sessionFactory);
	}
	
	public void setHibernateTemplate(HibernateTemplate hibernateTemplate) {
		HibernateUtil.hibernateTemplate = hibernateTemplate;
	}

	/**
	 * 带有查询条件的数量查询
	 * @param clazz
	 * @return
	 */
	public static int getCount(Class clazz, SearchObject search){

		DetachedCriteria criteria = DetachedCriteria.forClass(clazz);
		/*存放关联对象的criteria*/
		Map<String,DetachedCriteria> detachedCriteriaMap=new HashMap<String, DetachedCriteria>(1);

		for(SearchValue condition : search.getCondition()){

			if(condition.isBlank()) continue;
            addCondition(criteria,condition,detachedCriteriaMap);
		}

		criteria.setProjection(Projections.rowCount());
		List list = hibernateTemplate.findByCriteria(criteria);
		return list.size() > 0 ? ((Long)list.get(0)).intValue() : 0;
	}

	/**
	 * 只有排序的查询
	 * @param clazz		查询的对象
	 * @return
	 */
	public static List getPageObject(Class clazz, SearchObject search){

		DetachedCriteria criteria = DetachedCriteria.forClass(clazz);
		/*存放关联对象的criteria*/
		Map<String,DetachedCriteria> detachedCriteriaMap=new HashMap<String, DetachedCriteria>(1);

		for(SearchValue condition : search.getCondition()){

			if(condition.isBlank()) continue;
            addCondition(criteria,condition,detachedCriteriaMap);
		}

		Map<String, SearchValue.Order> order = search.getOrder();
		Iterator<String> iterator = order.keySet().iterator();
		String key;
		while(iterator.hasNext()){

			key = iterator.next();

			if(SearchValue.Order.ASC.equals(order.get(key))){
				criteria.addOrder(Order.asc(key));
			} else if(SearchValue.Order.DESC.equals(order.get(key))) {
				criteria.addOrder(Order.desc(key));
			}
		}

		return hibernateTemplate.findByCriteria(criteria, search.getPageNum()*search.getPageSize(), search.getPageSize());
	}

    private static void addCondition(DetachedCriteria criteria,SearchValue condition,Map<String,DetachedCriteria> detachedCriteriaMap){

		String[] names=condition.getName().split("\\.");
		if(names.length==2&&!detachedCriteriaMap.containsKey(names[0])){
			if(!"{alias}".equals(names[0])){
				detachedCriteriaMap.put(names[0],criteria.createAlias(names[0],names[0]));
			}
		}if(names.length>2){
			/*TODO 待完善，多级关联有问题*/
			StringBuffer sb=new StringBuffer();
			names=Arrays.copyOf(names,names.length-1);
			for(String nameTmp:names){
				if(sb.length()>0)
				{
					sb.append("."+nameTmp);
				}else {
					sb.append(nameTmp);
				}
				if(!detachedCriteriaMap.containsKey(sb.toString())){
					detachedCriteriaMap.put(sb.toString(),criteria.createAlias(sb.toString(),nameTmp));
				}
			}
		}

        switch (condition.getPattern()){
            case LIKE:
                criteria.add(Restrictions.like(condition.getName(), "%" + condition.getValue() + "%"));
                break;
            case IN:
                if(condition.getValue() instanceof Collection){
                    criteria.add(Restrictions.in(condition.getName(), (Collection)condition.getValue()));
                } else {
                    criteria.add(Restrictions.in(condition.getName(), (Object[]) condition.getValue()));
                }
                break;
			case EQUAL:
				criteria.add(Restrictions.eq(condition.getName(), condition.getValue()));
				break;
			case NOTEQUAL:
				criteria.add(Restrictions.ne(condition.getName(), condition.getValue()));
				break;
            case GT:
                criteria.add(Restrictions.gt(condition.getName(),condition.getValue()));
                break;
            case GE:
                criteria.add(Restrictions.ge(condition.getName(),condition.getValue()));
                break;
            case LT:
                criteria.add(Restrictions.lt(condition.getName(),condition.getValue()));
                break;
            case LE:
                criteria.add(Restrictions.le(condition.getName(),condition.getValue()));
                break;
            case SQL:
                criteria.add(Restrictions.sqlRestriction(condition.getName()));
                break;
            case NULL:
                criteria.add(Restrictions.isNull(condition.getName()));
                break;
            case NOTNULL:
                criteria.add(Restrictions.isNotNull(condition.getName()));
                break;
            default:
                break;
        }
    }
	
	public static Object execute(final String sql, final Map<String, Object> param){
		
		return hibernateTemplate.execute(new HibernateCallback() {

			@Override
			public Object doInHibernate(Session session) throws HibernateException,
					SQLException {

				Query query = session.createQuery(sql);

				Iterator<String> iterator = param.keySet().iterator();
				while (iterator.hasNext()) {

					String key = iterator.next();
					Object value = param.get(key);
					if (value instanceof Collection) {
						query.setParameterList(key, (Collection) value);
					} else if (value instanceof Object[]) {
						query.setParameterList(key, (Object[]) value);
					} else {
						query.setParameter(key, value);
					}
				}

				return query.executeUpdate();
			}
		});
	}

	public static Object executeSql(final String sql, final Map<String, Object> param){

		return hibernateTemplate.execute(new HibernateCallback() {

			@Override
			public Object doInHibernate(Session session) throws HibernateException,
					SQLException {

				Query query = session.createSQLQuery(sql);

				Iterator<String> iterator = param.keySet().iterator();
				while(iterator.hasNext()){

					String key = iterator.next();
					Object value = param.get(key);
					if(value instanceof Collection){
						query.setParameterList(key, (Collection)value);
					} else if(value instanceof Object[]) {
						query.setParameterList(key, (Object[])value);
					} else {
						query.setParameter(key, value);
					}
				}
				if(sql.trim().toLowerCase().startsWith("select")){
					return query.list();
				}
				return query.executeUpdate();
			}
		});
	}
	
	public static Object executeFind(final String sql, final Map<String, Object> param){
		
		return hibernateTemplate.execute(new HibernateCallback() {
			
			@Override
			public Object doInHibernate(Session session) throws HibernateException,
					SQLException {
				
				Query query = session.createQuery(sql);
				
				Iterator<String> iterator = param.keySet().iterator();
				while(iterator.hasNext()){
					
					String key = iterator.next();
					Object value = param.get(key);
					if(value instanceof Collection){
						query.setParameterList(key, (Collection)value);
					} else if(value instanceof Object[]) {
						query.setParameterList(key, (Object[])value);
					} else {
						query.setParameter(key, value);
					}
				}
				List result = query.list();
				session.clear();
				session.close();
				return result;
			}
		});
	}
}
